/**
 * @author Nicoleta Preda (andapreda@gmail.com)
 */
package dataguide;
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

import customization.Constants;

import java.awt.HeadlessException;
import java.io.File;
import java.util.*;

/* a bug: in the case there are attributes with the same name for different nodes or an attribute and an element with the same name: bug*/
/* so add the type and the name of the element for the attributes*/
public class DataGuide extends DefaultHandler{
	Node root=new Node("root", Node.DG_ROOT, null);
	/** list of all nodes which have text values underneath **/
	HashSet<Node> nodesWithTextValues;
	StringBuffer buff=null;
	Stack<Node> st=new Stack<Node>();
	
	public DataGuide()
	{	
		nodesWithTextValues=new HashSet<Node>();
		st.push(root);
		
	}
	
	public void clear(){
		buff=null;
		
		st.clear();
		st.push(root);
	}

	public void makeparse(String file) throws Exception
  	{
      		SAXParser parser=new SAXParser();
      		clear();
     
      		System.setProperty( "org.xml.sax.driver","org.apache.xerces.parsers.SAXParser"	 );
   	   	     	  
   	  		parser.setContentHandler(this);
   	  		/**
   	  		try {
   				parser.setFeature("http://xml.org/sax/features/validation", true);
   				parser.setFeature("http://xml.org/sax/features/namespaces", true);   				
   				parser.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", true);
   				parser.setFeature("http://apache.org/xml/features/"+ "validation/schema", true);
                parser.setFeature("http://apache.org/xml/features/"+ "validation/schema-full-checking",true);               
 				} catch (SAXException e) {
   				System.err.println("Cannot activate validation."); 
 				}
 				PSVIProvider provider=(PSVIProvider)parser;	
 			**/
   	  		parser.parse(file);    	 
  	}

	/*****************************************************************************************/
							/**	PARSE ELEMENT	*/
	/****************************************************************************************/
	public void startElement (String uri, String local, String qName, Attributes atts)
	{
		flushText();
		Node current=null;
		
		/** by construction, our dataguide is never empty  **/
		if(! st.empty()) 
    		 	{
				Node parent=(Node)st.peek();
    		 		current=parent.getOrCreate(local,Node.ELEM);
    		 		st.push(current);
    		 	}
    		 	
		 /* parse the attributes*/
		 parseAttributes(current,atts); 		
	}
	
	public void endElement(String uri, String localName, String qName) 
	{
		flushText();
		st.pop();  		
	}	
	
	
	/*****************************************************************************************/
							/**	PARSE ATTTRIBUTES	*/
	/****************************************************************************************/
	public void parseAttributes(Node parent, Attributes attribs)
  	{ 
		for ( int i=0;i<attribs.getLength();i++)
    	{
    		String local=attribs.getLocalName(i);  
    		String value=attribs.getValue(i);
    		Node sonNode=parent.getOrCreate(local, Node.ATT);
    		if(value!=null) {
    			value=value.trim();
    			sonNode.getOrCreate(value, Node.VALUE);
    			if(!nodesWithTextValues.contains(sonNode)){ nodesWithTextValues.add(sonNode); }
    		}
    	}
		
  	}
	/*****************************************************************************************/
							/**	PARSE TEXT	*/
	/****************************************************************************************/
	public void characters (char[] ch, int start, int length)  {
		if(buff==null) buff=new StringBuffer();
		buff.append(ch,start,length);
  	}
	public void flushText(){
		if(buff==null) return;
		if(st.empty()) return;
		
		Node parent=st.peek();
		parent.getOrCreate(buff.toString(), Node.VALUE);
		nodesWithTextValues.add(parent);
		buff=null;
	}
	
	public void parseText(String value)
  	{
  	 	StringTokenizer st = new StringTokenizer(value);
  	 	while (st.hasMoreTokens()) {
     				 String s=st.nextToken();
     				 if(!(s==null)){
     		
     				 		}
     				 }		 				 
  	 }	
	
	
	
	public String toString(){
		StringBuffer b= new StringBuffer();
		for(Node n: nodesWithTextValues){
			b.append(n.toString()+"\n***********\n");
		}
		return b.toString();
	}
	

	
	/*****************************************************************************************/
							/**	DTD MAIN */
	/****************************************************************************************/
	public static void addAllFilesFromDirectoryToTheDataguide(DataGuide dg, String dirPath) throws Exception{
		File folder = new File(dirPath);
		File[] listOfFiles = folder.listFiles();
			int j=0;
		    for (int i = 0; i < listOfFiles.length; i++) {
		      if (listOfFiles[i].isFile() && ! listOfFiles[i].getName().startsWith(".")) {
		    	  	 j++;
		    	  	 String file=listOfFiles[i].getName();
		    	     dg.makeparse(dirPath+file);
		    	     System.out.println("File "+j+" " + file);
		      } 
		    }
	}
	
	public static ArrayList<DataGuide> oneDataGuidePerXMLFile(String dirPath) throws Exception{
		ArrayList<DataGuide> allDGs= new ArrayList<DataGuide>();
		File folder = new File(dirPath);
		File[] listOfFiles = folder.listFiles();
			int j=0;
		    for (int i = 0; i < listOfFiles.length; i++) {
		      if (listOfFiles[i].isFile() && ! listOfFiles[i].getName().startsWith(".")) {
		    	     DataGuide dg=new DataGuide();
		    	  	 j++;
		    	  	 String file=listOfFiles[i].getName();
		    	     dg.makeparse(dirPath+file);
		    	     if(file.contains("Bono")) System.out.println("\n\n\n\n\n\nFile "+j+" " + file+"\n"+dg.toString()); 
		      } 
		    }
		return allDGs;
	}
	
	public static void main(String[] args) throws Exception
	{
		/**DataGuide dg=new DataGuide();
		addAllFilesFromDirectoryToTheDataguide(dg, Constants.pathToCallResults); 
		String s=dg.toString();
		System.out.println(s);
		**/
		oneDataGuidePerXMLFile(Constants.pathToCallResults);
		
		
		
			}    
}
